#include "huffmanZ.h"

using namespace dataStructureZ::DirTableZ;
using dataStructureZ::AATree::AATreeZ;

namespace dataStructureZ
{
	inline char* getFileName(char * path)
	{
		path += strlen(path);
		while(*(--path)!=SEP);
		return path + 1;
	}
	
	inline const char* getFileName(const char * path, char sep = SEP)
	{
		path += strlen(path);
		while(*(--path)!=sep);
		return path + 1;
	}
	
	inline char* getFileNamePostfix(char * path)
	{
		char * result = path + strlen(path);
		while(result >= path)
		{
			if(*result == '.')
				return result + 1;
			--result;
		}
		return NULL;
	}
	
	inline const char* getFileNamePostfix(const char * path)
	{
		const char * result = path + strlen(path);
		while(result >= path)
		{
			if(*result == '.')
				return result + 1;
			--result;
		}
		return NULL;
	}
	
	inline char* getFileNameWithoutPostfixWithMalloc(const char * path)
	{
		char * newStr = (char*) malloc((strlen(path) + 3) * sizeof(char));
		strcpy(newStr, path);
		getFileNamePostfix(newStr)[-1] = '\0';
		
		return newStr;
	}
	
	inline char* getPathWithMalloc(const char * path)
	{
		char * newStr = (char*) malloc((strlen(path) + 5) * sizeof(char));
		strcpy(newStr, path);
		getFileName(newStr)[-1] = '\0';
		return newStr;
	}
	
	inline bool linuxDirChk(const char* path)
	{
		#if defined(_WIN32) || defined(_WINDOWS_)
			return false;
		#else
			DIR* pdir = opendir(path);
			if(pdir != nullptr)
			{
				closedir(pdir);
				return true;
			}
			return false;
		#endif
	}
	
	class OrzFile
	{
		public:DirTable				userIndex;
		public:const char*			openedByOrzFilePath;
		
		public:OrzFile(void):	//create a empty orz file.
		userIndex(), openedByOrzFilePath(nullptr) {}
		
		public:~OrzFile(void)
		{
			delete openedByOrzFilePath;
		}
		
		public:FileSystemInfoBlock* add(const char* filePath, const char* addToPath)
		{
			std::ifstream ifs(filePath, std::ios_base::in | std::ios_base::binary);
			
			if(ifs && !linuxDirChk(filePath))
			{
				//--orz file and get new FileSystemInfoBlock with new CodeInfo and fileData.--
				ifs.seekg(0l, std::ios::end);
				uint64_t fileSize = ifs.tellg();
				ifs.seekg(0l, std::ios::beg);
				
				uint8_t* buffer = new uint8_t[fileSize];
				ifs.read(reinterpret_cast<char*>(buffer), fileSize);
				ifs.close();
				
				FileSystemInfoBlock* newFSIB = new FileSystemInfoBlock(new CodeInfo);
				newFSIB->sourceFileByteSize = fileSize;
				
				std::cout<<"orz Manager>> Read file succeeded. Starting encoding..."<<std::endl;
				
				uint64_t orzedDataByteSize;
				if(fileSize > 0)
				{
					deque< tupleIndex<uint64_t, uint8_t> > countOfBtye;
					
					for(uint64_t i=0 ; i<256 ; ++i)
						countOfBtye.push_back(tupleIndex<uint64_t, uint8_t>(0, i));
					for(uint64_t i=0 ; i<fileSize ; ++i)
						++(*(countOfBtye.begin() + buffer[i])).key;
					
					huffmanTreeZ<uint8_t, uint64_t> codeTree(countOfBtye);
					codeTree.bit_encode(newFSIB->code->code);
					
					std::cout<<"orz Manager>> Encoding succeeded. Starting orzing..."<<std::endl;
					
					uint8_t* fileData = new uint8_t[fileSize];
					
					ifs.seekg(0l, std::ios::beg);
					ArrayBitController<uint64_t> abcOut(fileSize * 8, fileData), tmp;
					
					uint64_t seg, bit=0/*orzed bit size*/;
					
					for(uint64_t byte=0 ; byte<fileSize ; ++byte)
					{
						ArrayBitController<uint8_t>& abcIn = newFSIB->code->code[buffer[byte]];
						seg = bit;
						for(; bit-seg < abcIn.bitLen ; ++bit)
							abcOut.set(bit, abcIn.get(bit-seg));
					}
					
					newFSIB->data = fileData;
					newFSIB->bitSize = bit;
					orzedDataByteSize = upDiv(bit, (uint64_t)8);
				}
				else//empty file
				{
					std::cout<<"orz Manager>> Encoding succeeded. Starting orzing..."<<std::endl;
					newFSIB->data = nullptr;
					newFSIB->bitSize = 0;
					orzedDataByteSize= 0;
				}
				
				//----add new FileSystemInfoBlock to index----
				
				const char* fileName = getFileName(filePath);
				if(strcmp(addToPath, "/"))
				{
					char* filePathInOrzFile = new char[sizeof(char) * (strlen(addToPath) + 1 + strlen(fileName) + 1)];
					
					filePathInOrzFile[0] = '\0';
					strcat(strcat(strcat(filePathInOrzFile, addToPath), "/"), fileName);
					
					userIndex.insert(filePathInOrzFile, newFSIB);
					delete filePathInOrzFile;
				}
				else
				{
					char* filePathInOrzFile = new char[sizeof(char) * (1 + strlen(fileName) + 1)];
					
					filePathInOrzFile[0] = '\0';
					strcat(strcat(filePathInOrzFile, addToPath), fileName);
					
					userIndex.insert(filePathInOrzFile, newFSIB);
					delete filePathInOrzFile;
				}
				#if defined(__ANDROID__)
				std::cout
					<<"Orz Manager>> File \""
					<<std::left<<std::setw(57)<<(std::string(fileName + std::string("\" orzed successfully.")))
					<<std::endl<<std::left<<"Orz Manager>> Total at"<<std::endl<<std::right<<std::setw(16)<<orzedDataByteSize<<" / "
					<<std::left<<std::setw(16)<<fileSize
					<<" Bytes are orzed, rate="
					<<(double)orzedDataByteSize / (double)fileSize * 100.0
					<<"%"
					<<std::endl;
				#else
				std::cout
					<<"Orz Manager>> File \""
					<<std::left<<std::setw(90)<<(std::string(fileName + std::string("\" orzed successfully.")))
					<<std::endl<<std::left<<"Orz Manager>> Total at"<<std::right<<std::setw(22)<<orzedDataByteSize<<" / "
					<<std::left<<std::setw(22)<<fileSize
					<<" Bytes are orzed, rate="
					<<(double)orzedDataByteSize / (double)fileSize * 100.0
					<<"%"
					<<std::endl;
				#endif
				return newFSIB;
			}
			else 
			{
				addFloader(filePath, addToPath);
				return nullptr;
			}
		}
		
		#if defined (_WINDOWS_) || defined (_WIN32)
		public:void addFloader_(const char* dirPath, const char* addToPath, std::deque<std::string>& stkSubDIRName)
		{
			std::string sdir = std::string(dirPath);
			std::string innerPath(addToPath);
			if(innerPath != "/") innerPath += '/';
			innerPath += getFileName(dirPath);
			
			for
			(
				std::deque<std::string>::const_iterator i = stkSubDIRName.begin();
				i != stkSubDIRName.end();
				++i
			)
			{
				innerPath += '/' + *i;
				
				sdir += SEP + *i;
			}	sdir += sSEP "*.*";
			
			intptr_t aDIR;
			_finddata_t aItem;
			aDIR = _findfirst(sdir.c_str(), &aItem);
			
			if(aDIR == -1) return;
			
			do
			{
				if
				(
					strcmp(aItem.name,  ".") && 
					strcmp(aItem.name, "..")
		        )	//floader
		        {
		        	if(aItem.attrib & _A_SUBDIR)
					{
						stkSubDIRName.push_back(std::string(aItem.name));
						userIndex.createFloader(std::string(innerPath + std::string("/") + std::string(aItem.name)).c_str());
			        	addFloader_(dirPath, addToPath, stkSubDIRName);
						stkSubDIRName.pop_back();
					} else add(std::string(sdir.substr(0, sdir.length()-3) + std::string(aItem.name)).c_str(), innerPath.c_str());
				}
			}	while(_findnext(aDIR, &aItem) == 0);
			_findclose(aDIR);
		}
		
		public:void addFloader(const char* dirPath, const char* addToPath)
		{
			std::deque<std::string> stkSubDIRName;
			addFloader_(dirPath, addToPath, stkSubDIRName);
		}
		#else
		public:void addFloader(const char* dirPath, const char* addToPath)
		{
			std::deque<DIR*> stkDIR;
			std::deque<std::string> stkInnerPath;
			stkDIR.push_back(opendir(dirPath));
			stkInnerPath.push_back(getFileName(dirPath));
			
			dirent* aItem=nullptr;
			do
			{
				while((aItem=readdir(stkDIR.back())) != nullptr)
				{
					if(aItem->d_type == DT_DIR)
					{	//floader
						if(strcmp(aItem->d_name, ".") && strcmp(aItem->d_name, ".."))
						{
							std::string outerPath(dirPath);
							std::string innerPath(addToPath);
							if(innerPath != "/") innerPath += '/';
							innerPath += *stkInnerPath.begin();
							for
							(
								std::deque<std::string>::const_iterator i = stkInnerPath.begin() + 1;
								i != stkInnerPath.end();
								++i
							)
							{
								innerPath += '/' + *i;
								outerPath += SEP + *i;
							}
							outerPath += SEP;
							outerPath += aItem->d_name;
							innerPath += '/';
							innerPath += aItem->d_name;
							
							userIndex.createFloader(innerPath.c_str());
							stkDIR.push_back(opendir(outerPath.c_str()));
							stkInnerPath.push_back(aItem->d_name);
						}
					}
					else
					{	//file
						std::string outerPath(dirPath);
						std::string innerPath(addToPath);
						if(innerPath != "/") innerPath += '/';
						innerPath += *stkInnerPath.begin();
						for
						(
							std::deque<std::string>::const_iterator i = stkInnerPath.begin() + 1;
							i != stkInnerPath.end();
							++i
						)
						{
							innerPath += '/' + *i;
							outerPath += SEP + *i;
						}
						outerPath += SEP;
						outerPath += aItem->d_name;
						
						add(outerPath.c_str(), innerPath.c_str());
					}
				}
				
				closedir(stkDIR.back());
				stkDIR.pop_back();
				stkInnerPath.pop_back();
			}	while(!stkDIR.empty());
		}
		#endif
		
		public:static void unorzEachFloader(DirTable* nowAt, const char* unorzTo, std::deque<std::string>& layer)
		{
			std::string outerPath(unorzTo);
			std::string t; 
			for
			(
				std::deque<std::string>::const_iterator i=layer.begin(), j=i;
				i != layer.end();
				++i
			)
			{
				t = *i;
				if(i!=j || outerPath[outerPath.length()-1]!=SEP)
					outerPath += SEP;
				outerPath += *i;
			}
			
			for
			(
				AATreeZ<fileSystem_node>::iterator i=nowAt->list.begin();
				i != nowAt->list.end();
				++i
			)
			{
				if((*i).type)	//file
					unorzFile(&(*i), outerPath.c_str());
				else
				{				//floader
					layer.push_back(std::string((*i).name));
					mkDir((outerPath + SEP + (*i).name).c_str());
					std::cout<<"orz Manager>> Directory \""<<outerPath<<SEP<<(*i).name<<"\" created successfully."<<std::endl;
					unorzEachFloader((*i).data.table, unorzTo, layer);
					layer.pop_back();
				}
			}
		}
		
		public:static void unorz(fileSystem_node* target, const char* unorzTo = "." sSEP)
		{
			if(target->type)
				unorzFile(target, unorzTo);
			else unorzFloader(target, unorzTo);
		}
		
		public:void unorz(const char* innerPath)
		{
			unorz(userIndex.getNode(innerPath));
		}
		
		public:static void unorzFloader(fileSystem_node* fsnode, const char* unorzTo = "." sSEP)
		{
			if(fsnode != nullptr)
			{
				std::string rootDir(std::string(unorzTo) + SEP + fsnode->name);
				std::cout<<"orz Manager>> Directory \""<<rootDir<<"\" created successfully."<<std::endl;
				mkDir(rootDir.c_str());
				DirTable* dir = fsnode->data.table;
				
				if(dir != nullptr)
				{
					std::deque<std::string> dirLayer;
					dirLayer.push_back(std::string(fsnode->name));
					
					unorzEachFloader(dir, unorzTo, dirLayer);
				}
			}
		}
		
		public:void unorzFloader(const char* innerPath, const char* unorzTo = "." sSEP)
		{
			DirTable* dir = userIndex.openDir(innerPath);
			
			if(dir != nullptr)
			{
				std::deque<std::string> dirLayer;
				std::string s(getFileName(innerPath, '/'));
				dirLayer.push_back(s);
				
				unorzEachFloader(dir, unorzTo, dirLayer);
			}
		}
		
		public:static bool unorzFile(fileSystem_node* fsnode, const char* unorzTo = "." sSEP)
		{
			if(fsnode != nullptr)
			{
				FileSystemInfoBlock *file = fsnode->data.element;
				const char* fileName = fsnode->name;
				char *const to = new char[strlen(unorzTo) + strlen(fileName) + 2];
				
				strcpy(to, unorzTo);
				if(to[strlen(to)-1] != SEP)
					strcat(to, sSEP);
				strcat(to, fileName);
				mkDir(unorzTo);
				std::ofstream ofs(to, std::ios_base::trunc | std::ios_base::binary);
				if(ofs)
				{
					if(file->data != nullptr)
					{
						huffmanTreeZ<uint8_t, uint64_t> reCodeTree(file->code->code);
						uint8_t* buffer = new uint8_t[file->sourceFileByteSize];
						
						ArrayBitController<uint64_t> abcIn(file->bitSize, file->data);
						for(uint64_t i=0, j=0; i<file->bitSize;)	//for each byte in fileData
							buffer[j++] = reCodeTree.readByte(abcIn, i);
						
						//-------------------------------------------------dump
						
						ofs.write(reinterpret_cast<char*>(buffer), sizeof(uint8_t) * file->sourceFileByteSize);
						
						delete buffer;
						delete to;
					}
					ofs.close();
					std::cout<<"Orz Manager>> \""<<fileName<<"\" unorzed successfully."<<endl;
				}
				else
				{
					delete to;
					std::cout<<to<<std::endl;
					//throw "I/O Error: file open fault.";
				}
				
				return true;
			}	else return false;
		}
		
		public:bool unorzFile(const char* innerPath, const char* unorzTo = "." sSEP)
		{
			return unorzFile(userIndex.file_node(innerPath), unorzTo);
		}
		
		public:void open(const char* orzFilePath)
		{
			userIndex.clear(); 
			std::ifstream ifs(orzFilePath, std::ios_base::binary);
			if(ifs)
			{
				uint64_t fileByteSize = 0;
				uint64_t emptyDirInfoByteSize = 0;
				uint64_t fileDataBlockAreaByteSize = 0;
				ifs.seekg(0l, std::ios::end);
				fileByteSize = ifs.tellg();
				ifs.seekg(-sizeof(emptyDirInfoByteSize), std::ios::end);
				ifs.read(reinterpret_cast<char*>(&emptyDirInfoByteSize), sizeof(uint64_t));
				ifs.close();
				ifs.open(orzFilePath, std::ios_base::binary);
				if(!ifs) throw "I/O Error: File open fault.";
				
				fileDataBlockAreaByteSize = fileByteSize - sizeof(uint64_t) - emptyDirInfoByteSize;
				
				char tmp;
				while(static_cast<uint64_t>(ifs.tellg()) < fileDataBlockAreaByteSize)
				{
					std::string name("");
					while((static_cast<void>(ifs.read(reinterpret_cast<char*>(&tmp), sizeof(char))), tmp))
						name += tmp;
					
					FileSystemInfoBlock* newFSIB = new FileSystemInfoBlock(new CodeInfo);
					ifs.read(reinterpret_cast<char*>(&newFSIB->bitSize), sizeof(uint64_t));
					ifs.read(reinterpret_cast<char*>(&newFSIB->sourceFileByteSize), sizeof(uint64_t));
					
					if(newFSIB->sourceFileByteSize > 0)
					{
						uint8_t j = 0, byteCount = 0;
						do	//for each code
						{
							ifs.read(reinterpret_cast<char*>(&newFSIB->code->code[j].bitLen), sizeof(uint8_t));
							
							byteCount = upDiv
							(
								newFSIB->code->code[j].bitLen, 
								(uint8_t)8
							);
							
							if(byteCount > 0)
							{
								newFSIB->code->code[j].data = new uint8_t[byteCount];
								ifs.read
								(
									reinterpret_cast<char*>(newFSIB->code->code[j].data), 
									sizeof(uint8_t) * byteCount
								);
							}
						}	while(j++ < 255);
					
						newFSIB->data = new uint8_t[upDiv(newFSIB->bitSize, (uint64_t)8)];
						ifs.read(reinterpret_cast<char*>(newFSIB->data), sizeof(uint8_t) * upDiv(newFSIB->bitSize, (uint64_t)8));
					}
					else newFSIB->data = nullptr;
					
					userIndex.insert(name.c_str(), newFSIB);
				}
				
				char tmpc;
				std::string emptyDirInnerPath;
				while(static_cast<uint64_t>(ifs.tellg()) < fileDataBlockAreaByteSize + emptyDirInfoByteSize)
				{
					emptyDirInnerPath = "";
					while(static_cast<void>(ifs.read(&tmpc, sizeof(char))), tmpc != '\0')
						emptyDirInnerPath += tmpc;
					userIndex.createFloader(emptyDirInnerPath.c_str());
				}
				
				ifs.close();
				
				openedByOrzFilePath = strcpy(new char[strlen(orzFilePath)+1], orzFilePath);
			}	else throw "I/O Error: File open fault.";
		}
		
		public:OrzFile(const char* orzFilePath):
		userIndex(), openedByOrzFilePath(nullptr)
		{
			open(orzFilePath);
		}
		/*
		public:static void reset_depth(DirTable* father, fileSystem_node& startAt)
		{
			startAt.depth = father->depth;
			
			if(!startAt.type)
			{
				DirTable* nowAt = startAt.data.table;
				nowAt->depth = startAt.depth + 1;
				for
				(
					AATreeZ<fileSystem_node>::iterator i = nowAt->list.begin();
					i != nowAt->list.end();
					++i
				)
				{
					if(!(*i).type)
					{
						(*i).depth = nowAt->depth;
						reset_depth(nowAt, *i);
					}
				}
			}
		}
		*/
		public:static void dumpEachFloader
		(
			std::ofstream& ofs, 
			std::deque<const char*>& pathNameStack, 
			std::deque<std::string>& emptyFloaderList, 
			const DirTable* nowAt
		)
		{
			if(!nowAt->list.isEmpty())
			{
				for
				(
					AATreeZ<fileSystem_node>::iterator i = nowAt->list.begin();
					i != nowAt->list.end();
					++i
				)
				{
					if((*i).type)	//file, dump
					{
						//-----------------name-----------------
						for
						(
							std::deque<const char*>::const_iterator j = pathNameStack.begin();
							j != pathNameStack.end();
							++j
						)
						{
							ofs.write("/", sizeof(char));
							ofs.write(*j, sizeof(char) * strlen(*j));				//without '\0'
						}
						ofs.write("/", sizeof(char));
						ofs.write((*i).name, sizeof(char) * (strlen((*i).name)+1));	//with '\0'
						
						//-----------------bitSize--------------
						ofs.write(reinterpret_cast<char*>(&(*i).data.element->bitSize), sizeof(uint64_t));
						//-----------------sourceFileByteSize---
						ofs.write(reinterpret_cast<char*>(&(*i).data.element->sourceFileByteSize), sizeof(uint64_t));
						//-----------------CodeInfo-------------
						uint8_t j = 0;
						if((*i).data.element->sourceFileByteSize > 0) 
						{
							do	//for each code
							{
								ofs.write(reinterpret_cast<char*>(&(*i).data.element->code->code[j].bitLen), sizeof(uint8_t));
								ofs.write
								(
									reinterpret_cast<char*>((*i).data.element->code->code[j].data), 
									sizeof(uint8_t) * upDiv
									(
										(*i).data.element->code->code[j].bitLen, 
										(uint8_t)8
									)
								);
							}	while(j++ < 255);
						//-----------------fileData------------
							ofs.write(reinterpret_cast<char*>((*i).data.element->data), sizeof(uint8_t) * upDiv((*i).data.element->bitSize, (uint64_t)8));
						//-----------------end------------------
						}
					}
					else			//floader, recurs
					{
						pathNameStack.push_back((*i).name);
						dumpEachFloader(ofs, pathNameStack, emptyFloaderList, (*i).data.table);
					}
				}
			}
			else
			{
				std::string emptyPathName("");
				for
				(
					std::deque<const char*>::const_iterator j = pathNameStack.begin();
					j != pathNameStack.end();
					++j
				)
				{
					emptyPathName += "/";
					emptyPathName += *j;
				}
				emptyFloaderList.push_back(emptyPathName);
			}
			pathNameStack.pop_back();
		}
		
		public:static void dumpEachFloader
		(
			std::ofstream& ofs, 
			std::string& spath,
			std::stack<const char*>& pathNameStack, 
			std::deque<std::string>& emptyFloaderList, 
			const DirTable* nowAt
		)
		{
			if(!nowAt->list.isEmpty())
			{
				for
				(
					AATreeZ<fileSystem_node>::iterator i = nowAt->list.begin();
					i != nowAt->list.end();
					++i
				)
				{
					if((*i).type)	//file, dump
					{
						//-----------------name-----------------
						ofs.write(spath.c_str(), sizeof(char) * spath.length());
						ofs.write("/", sizeof(char));
						ofs.write((*i).name, sizeof(char) * (strlen((*i).name)+1));	//with '\0'
						//-----------------bitSize--------------
						ofs.write(reinterpret_cast<char*>(&(*i).data.element->bitSize), sizeof(uint64_t));
						//-----------------sourceFileByteSize---
						ofs.write(reinterpret_cast<char*>(&(*i).data.element->sourceFileByteSize), sizeof(uint64_t));
						//-----------------CodeInfo-------------
						uint8_t j = 0;
						if((*i).data.element->sourceFileByteSize > 0) 
						{
							do	//for each code
							{
								ofs.write(reinterpret_cast<char*>(&(*i).data.element->code->code[j].bitLen), sizeof(uint8_t));
								ofs.write
								(
									reinterpret_cast<char*>((*i).data.element->code->code[j].data), 
									sizeof(uint8_t) * upDiv
									(
										(*i).data.element->code->code[j].bitLen, 
										(uint8_t)8
									)
								);
							}	while(j++ < 255);
						//-----------------fileData------------
							ofs.write(reinterpret_cast<char*>((*i).data.element->data), sizeof(uint8_t) * upDiv((*i).data.element->bitSize, (uint64_t)8));
						//-----------------end------------------
						}
					}
					else			//floader, recurs
					{
						spath += '/';
						spath += (*i).name;
						pathNameStack.push((*i).name);
						dumpEachFloader(ofs, spath, pathNameStack, emptyFloaderList, (*i).data.table);
					}
				}
			}	else emptyFloaderList.push_back(spath);
			if(!pathNameStack.empty())
			{
				spath = spath.substr(0, spath.length() - strlen(pathNameStack.top()) - 1);
				pathNameStack.pop();
			}
		}
		
		public:void dump(const char* filePath = "." sSEP "newPackage.orz")
		{
			std::ofstream ofs(filePath, std::ios_base::trunc | std::ios_base::binary);
			
			if(ofs)
			{
				std::stack<const char*> pathNameStack;
				std::deque<std::string> emptyFloaderList;
				std::string spath("");
				dumpEachFloader(ofs, spath, pathNameStack, emptyFloaderList, &userIndex);
				uint64_t emptyDirInfoByteSize = 0, tmp;
				for
				(
					std::deque<std::string>::const_iterator i = emptyFloaderList.begin();
					i != emptyFloaderList.end();
					++i
				)
				{
					tmp = ((*i).length()+1) * sizeof(char);	//+1 for '\0'
					emptyDirInfoByteSize += tmp;
					ofs.write((*i).c_str(), tmp);
				}
				
				ofs.write(reinterpret_cast<char*>(&emptyDirInfoByteSize), sizeof(emptyDirInfoByteSize));
				ofs.close();
			}	else throw "I/O Error: file open fault.";
		}
		
		public:static FileSystemInfoBlock* copyFile(FileSystemInfoBlock* fileBlk)
		{
			FileSystemInfoBlock* newblk = new FileSystemInfoBlock;
			
			newblk->bitSize = fileBlk->bitSize;
			newblk->sourceFileByteSize = fileBlk->sourceFileByteSize;
			
			newblk->code = new CodeInfo;
			
			uint8_t i=0;
			uint8_t byteSize;
			do
			{
				newblk->code->code[i].bitLen = fileBlk->code->code[i].bitLen;
				byteSize = upDiv(newblk->code->code[i].bitLen, (uint8_t)8);
				newblk->code->code[i].data = new uint8_t[byteSize];
				memcpy(newblk->code->code[i].data, fileBlk->code->code[i].data, byteSize);
			}	while((i++)<255);
			
			uint64_t dataByteSize = upDiv(newblk->bitSize, (uint64_t)8);
			newblk->data = new uint8_t[dataByteSize];
			memcpy(newblk->data, fileBlk->data, dataByteSize);
			
			return newblk;
		}
		
		public:static FileSystemInfoBlock* copyFile(FileSystemInfoBlock* fileBlk, FileSystemInfoBlock*& newblk)
		{
			newblk->bitSize = fileBlk->bitSize;
			newblk->sourceFileByteSize = fileBlk->sourceFileByteSize;
			
			newblk->code = new CodeInfo;
			
			if(fileBlk->data != nullptr)
			{
				uint8_t i=0;
				uint8_t byteSize;
				do
				{
					newblk->code->code[i].bitLen = fileBlk->code->code[i].bitLen;
					byteSize = upDiv(newblk->code->code[i].bitLen, (uint8_t)8);
					newblk->code->code[i].data = new uint8_t[byteSize];
					memcpy(newblk->code->code[i].data, fileBlk->code->code[i].data, byteSize);
				}	while(i++ < 255);
				
				uint64_t dataByteSize = upDiv(newblk->bitSize, (uint64_t)8);
				newblk->data = new uint8_t[dataByteSize];
				memcpy(newblk->data, fileBlk->data, dataByteSize);
			}	else newblk->data = nullptr;
			
			return newblk;
		}
		
		public:static DirTable* copyFloader(DirTable* from, DirTable*& to/*, size_t baseDepth*/)
		{
			fileSystem_node temp;
			
			//to->depth = baseDepth + 1;
			//temp.depth= to->depth;
			for
			(
				AATreeZ<fileSystem_node>::iterator i = from->list.begin();
				i != from->list.end();
				++i
			)
			{
				temp.type = (*i).type;
				temp.name = strcpy(new char[strlen((*i).name)+1], (*i).name);
				
				if((*i).type)
				{
					temp.data.element = new FileSystemInfoBlock;
					copyFile((*i).data.element, temp.data.element);
				}
				else
				{
					temp.data.table = new DirTable;
					copyFloader((*i).data.table, temp.data.table/*, temp.depth*/);
				}
				to->list.insertWithoutEnbalance(temp);
			}
			to->list.reLevel();
			return to;
		}
		
		public:bool remove(const char* innerPath, bool file_floader = true)
		{
			return userIndex.remove(innerPath, file_floader);
		}
		
		public:bool remove(fileSystem_node* targetNode)
		{
			return userIndex.remove(targetNode);
		}
		
		public:static void rename(fileSystem_node* target, DirTable* at, const char* newName)
		{
			at->rename(target, newName);
		}
		
		public:void rename(const char* innerPath, const char* newName)
		{
			DirTable* at = nullptr;
			fileSystem_node* target = userIndex.getNode(innerPath, &at);
			rename(target, at, newName);
		}
		
		public:void clear(void)
		{
			userIndex.clear();
		}
	};
};
